package club.calong.sanniu.service;

import club.calong.sanniu.http.request.UserRequest;
import club.calong.sanniu.pojo.Role;
import club.calong.sanniu.pojo.User;
import club.calong.sanniu.repository.AdminRepository;
import club.calong.sanniu.repository.RoleRepository;
import club.calong.sanniu.util.CacheUtils;
import club.calong.sanniu.util.Utils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashSet;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {

    @Value("${app.avatar.user}")
    String USER_AVATAR;

    @Value("${app.user.role}")
    String USER_ROLE;

    AdminRepository repository;

    PasswordEncoder passwordEncoder;

    RoleRepository roleRepository;

    private Role userRole;

    @Autowired
    public UserService(PasswordEncoder passwordEncoder,
                       AdminRepository repository,
                       RoleRepository roleRepository,
                       JavaMailSender mailSender) {
        this.passwordEncoder = passwordEncoder;
        this.repository = repository;
        this.roleRepository = roleRepository;
        this.mailSender = mailSender;
    }

    public User checkexits (String openid ) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.lambda().like(User::getOpenid,openid);
        User user =  repository.selectOne(userQueryWrapper);
        if(user != null)
            return user;
        return null;
    }
    public int wxregist (User user) {
        if (this.userRole == null) {
            QueryWrapper<Role> wrapper = new QueryWrapper<>();
            wrapper.eq(Role.ROLE_NAME, USER_ROLE);
            this.userRole = roleRepository.selectOne(wrapper);
        }
        user.setRoles(new HashSet<Integer>(){{
            add(userRole.getId());
        }});
        user.setRoleNames(new HashSet<String>(){{
            add(userRole.getName());
        }});
        user.setIntroduction("您好微信用户！");
        if (repository.insert(user) == 1) {
            return 1;
        }
        return -1;
    }
    public int registry(UserRequest user) {

        if (this.userRole == null) {
            QueryWrapper<Role> wrapper = new QueryWrapper<>();
            wrapper.eq(Role.ROLE_NAME, USER_ROLE);
            this.userRole = roleRepository.selectOne(wrapper);
        }

        if (checkCode(user.getEmail(), user.getCode())) {
            user.setAvatar(USER_AVATAR);
            user.setIntroduction("普通用户");
            user.setId(null);
            user.setRoles(new HashSet<Integer>(){{
                add(userRole.getId());
            }});
            user.setRoleNames(new HashSet<String>(){{
                add(userRole.getName());
            }});
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            if (repository.insert(convertUser(user)) == 1) {
                CacheUtils.getCodes().remove(user.getEmail());
                return 1;
            }
        } else {
            return 0;
        }
        return -1;
    }

    public int forget(UserRequest user) {
        if (this.userRole == null) {
            QueryWrapper<Role> wrapper = new QueryWrapper<>();
            wrapper.eq(Role.ROLE_NAME, USER_ROLE);
            this.userRole = roleRepository.selectOne(wrapper);
        }

        if (checkCode(user.getEmail(), user.getCode())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            user.setRoles(new HashSet<Integer>(){{
                add(userRole.getId());
            }});
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq(User.USERNAME,user.getUsername());
            if (repository.update(convertUser(user),wrapper) == 1) {
                CacheUtils.getCodes().remove(user.getEmail());
                return 1;
            }
        } else {
            return 0;
        }
        return -1;
    }

    public int revise(UserRequest user) {
        if (this.userRole == null) {
            QueryWrapper<Role> wrapper = new QueryWrapper<>();
            wrapper.eq(Role.ROLE_NAME, USER_ROLE);
            this.userRole = roleRepository.selectOne(wrapper);
        }
        
        if (checkCode(user.getEmail(), user.getCode())) {
            user.setRoles(new HashSet<Integer>(){{
                add(userRole.getId());
            }});
            return repository.updateById(convertUser(user));
        } else {
            return 0;
        }
    }

    private User convertUser (UserRequest request) {

        User user = new User();
        user.setId(request.getId());
        user.setAvatar(request.getAvatar());
        user.setIntroduction(request.getIntroduction());
        user.setName(request.getName());
        user.setUsername(request.getUsername());
        user.setPassword(request.getPassword());
        user.setRoles(request.getRoles());
        user.setEmail(request.getEmail());
        user.setPhone(request.getPhone());
        return user;
    }

    public boolean checkCode(String email, String code) {

        String _code = CacheUtils.getCodes().get(email);
        System.out.println("send code is:" +_code);
        System.out.println("user code is:" +code);
        if (_code != null && _code.equals(code)) {
            CacheUtils.getCodes().remove(email);
            return true;
        } else {
            return false;
        }
    }

    private final JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    String MAIL_USERNAME;

    private static final String MAIL_CONTENT = "<div style='width: 400px;height: 300px;background-color: #EEE, border: 1px solid #333; margin: 30px auto; padding-left: 30px; padding-right: 30px;'>" +
            "<h4>您收到来自【三牛网站】的注册验证码</h4>" +
            "<h1>#{code}</h1>" +
            "<h5>验证码将在#{timeout}分钟后过期，如非本人操作请直接忽略</h5>" +
            "</div>";

    @Value("${app.code-timeout}")
    Long CODE_TIMEOUT;

    final ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

    public boolean code(String email, String id) throws MessagingException {

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper  = new MimeMessageHelper(message);
        try {
            String code = Utils.generateCode(4);
            // 存储验证码
            CacheUtils.getCodes().put(email, code);

            service.schedule( () -> {
                CacheUtils.getCodes().remove(email);
            }, CODE_TIMEOUT, TimeUnit.SECONDS);
            // 存储客户端
            CacheUtils.getWaiters().put(id, email);
            service.schedule( () -> {
                CacheUtils.getWaiters().remove(id);
            }, 60, TimeUnit.SECONDS);

            helper.setSubject("【三牛网站】用户注册验证码");
            helper.setFrom(MAIL_USERNAME);
            helper.setTo(email);
            helper.setSentDate(Date.from(LocalDateTime.now().toInstant(ZoneOffset.ofHours(8))));
            helper.setText(MAIL_CONTENT.replace("#{code}", code)
                    .replace("#{timeout}", String.valueOf(CODE_TIMEOUT / 60)), true);
            mailSender.send(message);
            return true;
        } catch (Throwable e) {
            e.printStackTrace();
            return false;
        }
    }
}
